#ifndef __YIZHI_LOG_H__
#define __YIZHI_LOG_H__
#include<iostream>
#include<memory>
#include<vector>
#include<list>
#include<sstream>
#include<fstream>
#include"Singleton.h"
#include<map>
#include"util.h"
#include"thread.h"
#include"mutex.h"
#define SERVER_LOG_LEVEL(logger,level) \
            if(logger->getLevel()<=level) \
                Yizhi::LogEventWrap(Yizhi::LogEvent::ptr(new Yizhi::LogEvent(logger,level,Yizhi::GetThreadid(),Yizhi::GetFiberid(),\
                0,time(0),__LINE__,__FILE__,Yizhi::Thread::getName()))).getSS()
#define SERVER_LOG_DEBUG(logger) SERVER_LOG_LEVEL(logger,Yizhi::LogLevel::Level::DEBUG)
#define SERVER_LOG_INFO(logger)  SERVER_LOG_LEVEL(logger,Yizhi::LogLevel::Level::INFO)
#define SERVER_LOG_WARN(logger)  SERVER_LOG_LEVEL(logger,Yizhi::LogLevel::Level::WARN)
#define SERVER_LOG_ERROR(logger)  SERVER_LOG_LEVEL(logger,Yizhi::LogLevel::Level::ERROR)
#define SERVER_LOG_FATAL(logger)  SERVER_LOG_LEVEL(logger,Yizhi::LogLevel::Level::FATAL)


#define SERVER_LOG_FMT_LEVEL(logger,frm,level) \
            if(logger->getLevel()<=level) \
                Yizhi::LogEventWrap(Yizhi::LogEvent::ptr(new Yizhi::LogEvent(logger,level,Yizhi::GetThreadid(),Yizhi::GetFiberid() \
                0,time(0),___LINE__,__FILE__))).getEvent.format(frm,VA_ARGS_)


#define SERVER_LOG_FMT_DEBUG(logger,frm) SERVER_LOG_FMT_LEVEL(logger,Yizhi::LogLevel::Level::DEBUG,frm)
#define SERVER_LOG_FMT_INFO(logger,frm) SERVER_LOG_FMT_LEVEL(logger,Yizhi::LogLevel::Level::INFO,frm)
#define SERVER_LOG_FMT_WARN(logger,frm) SERVER_LOG_FMT_LEVEL(logger,Yizhi::LogLevel::Level::WARN,frm)
#define SERVER_LOG_FMT_ERROR(logger,frm) SERVER_LOG_FMT_LEVEL(logger,Yizhi::LogLevel::Level::ERROR,frm)
#define SERVER_LOG_FMT_FATAL(logger,frm) SERVER_LOG_FMT_LEVEL(logger,Yizhi::LogLevel::Level::FATAL,frm)

#define SERVER_LOG_ROOT() Yizhi::Loggermgr::GetInstance()->getroot()

#define SERVER_LOG_NAME(name) Yizhi::Loggermgr::GetInstance()->GetLogger(name);

namespace Yizhi{
class Logger;
    //日志级别
    class LogLevel{
        public:
        enum class Level{
            UNKNOW=1,
            DEBUG=2,
            INFO=3,
            WARN=4,
            ERROR=5,
            FATAL=6
        };
        static const char * Tostring(LogLevel::Level level);
        static LogLevel::Level FormString(const std::string &str);
    };


    
    class LogEvent{//          日志事件
        public:
        typedef std::shared_ptr<LogEvent> ptr;
        LogEvent(std::shared_ptr<Logger> logger
                ,LogLevel::Level level
                ,uint32_t pthreadid
                ,uint32_t fiberid,uint64_t elapse
                ,uint32_t time
                ,int32_t m_line
                ,const char *filename
                ,const std::string& ThreadName);

                //返回线程名
        const std::string &getThreadName(){return m_threadName;}

                //
        const char *getfilename(){return m_filename;}

        uint32_t getThreadId(){return m_pthreadId;}

        uint32_t getFiberId(){return m_fiberId;}

        uint32_t getTime(){return m_time;}
        uint64_t getelapse(){return m_elapse;}
        int32_t getline(){return m_line;}
        std::shared_ptr<Logger> getlogger(){return m_logger;}
        std::stringstream& getss(){return m_ss;}
        const std::string getcontent(){return m_ss.str();}
        LogLevel::Level getLevel(){return m_level;}
        void format(char *frm,...);
        void format(char *frm,va_list val);
        private:
        std::shared_ptr<Logger> m_logger;
        LogLevel::Level m_level;
        uint32_t m_pthreadId=0;               //线程号
        uint32_t m_fiberId=0;                //协程号
        uint64_t m_elapse=0;                   //从程序启动到现在的毫秒数
        uint32_t m_time=0;                    //时间戳
        int32_t  m_line=0;                    //行号
        const char * m_filename=nullptr;              //文件名
        std::string m_threadName;
        std::stringstream m_ss;
       
    };
    class LogEventWrap{
        public:
        LogEventWrap(LogEvent::ptr e);
        ~LogEventWrap();
        std::stringstream &getSS();
        LogEvent::ptr getEvent(){return m_event;}
        private:
        LogEvent::ptr m_event;
    };
    
    class LogFormatter{                     //日志格式
        public:
        typedef std::shared_ptr<LogFormatter> ptr;

        LogFormatter(const std::string &str);
        void init();
        std::string format(LogEvent::ptr event,LogLevel::Level level);
        public:

        class FormatItem{
            public:
            typedef std::shared_ptr<FormatItem> ptr;
            FormatItem(std::string frmstr=""){}
            virtual void format(std::ostream &os,LogEvent::ptr event,LogLevel::Level level)=0;
        };

        private:
        std::string m_pattern;
        std::vector<FormatItem::ptr> m_items;


    };

    class LogAppender{
        public:
        typedef Mutex MutexType;
        typedef std::shared_ptr<LogAppender> ptr;
        virtual ~LogAppender(){}

        virtual void log(LogEvent::ptr event,LogLevel::Level)=0;

        void setformat(LogFormatter::ptr format);
        void setformat(const std::string & fmt);
        LogFormatter::ptr getformatter();

        void setLevel(LogLevel::Level level){m_level=level;}
        LogLevel::Level getLevel(){return m_level;}


        protected:
        LogLevel::Level m_level=LogLevel::Level::DEBUG;
        LogFormatter::ptr m_format;
        MutexType m_mutex;
        
    };

    class Logger:public std::enable_shared_from_this<Logger>{ 
        friend class LoggerManager;                          //日志适配器
        public:
        typedef Mutex MutexType;

        typedef std::shared_ptr<Logger> ptr;


        Logger(const std::string &name="root");



        void log(LogEvent::ptr event,LogLevel::Level level);


        void setformat(LogFormatter::ptr format){m_format=format;}
        void setformat(const std::string & fmt);


        void Debug(LogEvent::ptr event);
        void Info(LogEvent::ptr event);
        void Warn(LogEvent::ptr event);
        void Error(LogEvent::ptr event);
        void Fatal(LogEvent::ptr event);


        void setAppender(LogAppender::ptr appender);
        void delAppender(LogAppender::ptr appender);
        void clearAppender();


        void setLevel(LogLevel::Level val){m_level=val;}
        LogLevel::Level getLevel(){return m_level;}


        private:
        std::string m_name;
        LogLevel::Level m_level;
        LogFormatter::ptr m_format;
        MutexType m_mutex;
        std::list<LogAppender::ptr> m_appender;
        Logger::ptr m_root;
        
    };

    class StdoutLogAppender: public LogAppender{
        public:
        void log(LogEvent::ptr event,LogLevel::Level)override;
    };
    class FileLogAppender:public LogAppender{
        public:
        typedef std::shared_ptr<FileLogAppender> ptr;
        FileLogAppender(const std::string &filename);
        bool reopen();
        void log(LogEvent::ptr event,LogLevel::Level)override;
        private:
        std::string m_filename;
        std::ofstream m_filestream;
        uint64_t last_time=0;
    };

    struct LogInit{
        void init();
        LogInit(){
            init();
        }
    };

    class LoggerManager{
      

        public:
        typedef Mutex MutexType;
        LoggerManager();
        Logger::ptr GetLogger(const std::string &name);
        Logger::ptr getroot(){return m_roots;}

        void delLogger(const std::string &name);

        private:
        std::map<std::string,Logger::ptr> m_logger;
        Logger::ptr m_roots;
        MutexType m_mutex;
    };
    typedef  Singleton<LoggerManager> Loggermgr;
}

#endif